#include "MPU6050.h"

I2C_TypeDef *MPU6050_I2Cx = I2C2;

double GYROZ_0 = 0;
uint16_t busytime = 0;
bool MPU6050_exist = false;

#define EV5 I2C_EVENT_MASTER_MODE_SELECT
#define EV6 I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED
#define EV7 I2C_EVENT_MASTER_BYTE_RECEIVED
#define EV8 I2C_EVENT_MASTER_BYTE_TRANSMITTING
#define EV8_2 I2C_EVENT_MASTER_BYTE_TRANSMITTED

// typedef struct
// {
//   uint32_t I2C_ClockSpeed; 时钟频率 低于 400000
//   uint16_t I2C_Mode;
//   uint16_t I2C_DutyCycle;            时钟占空比
//   uint16_t I2C_OwnAddress1;          自身地址
//   uint16_t I2C_Ack;                  使能响应
//   uint16_t I2C_AcknowledgedAddress;  指定地址长度 7或10
// }I2C_InitTypeDef;

// typedef struct
// {
//   uint16_t GPIO_Pin;             /*!< Specifies the GPIO pins to be configured.
//                                       This parameter can be any value of @ref GPIO_pins_define */

//   GPIOSpeed_TypeDef GPIO_Speed;  /*!< Specifies the speed for the selected pins.
//                                       This parameter can be a value of @ref GPIOSpeed_TypeDef */

//   GPIOMode_TypeDef GPIO_Mode;    /*!< Specifies the operating mode for the selected pins.
//                                       This parameter can be a value of @ref GPIOMode_TypeDef */
// }GPIO_InitTypeDef;

void MPU6050_waitEvent(uint32_t I2C_EVENT)
{
    uint16_t Timeout = 1000;
    while (I2C_CheckEvent(MPU6050_I2Cx, I2C_EVENT) != SUCCESS)
    {
        Timeout--;
        if (Timeout == 0)
        {
            GPIOC_myTest_on();
            // I2C_GenerateSTOP(MPU6050_I2Cx, ENABLE);
            break;
        }
    }
}

void MPU6050_waitBusy()
{
    uint8_t i;
    uint16_t Timeout = 1000;
    uint16_t SCL;
    uint16_t SDA;
    GPIO_InitTypeDef GPIO_InitStruct;
    OLED_ShowNum(1, 10, busytime, 3);
    while (I2C_GetFlagStatus(MPU6050_I2Cx, I2C_FLAG_BUSY))
    {
        Timeout--;
        if (Timeout == 0)
        {
            busytime++;
            GPIOC_myTest_on();
            I2C_Cmd(MPU6050_I2Cx, DISABLE);
            if (busytime > 100)
            {
                GPIOC_myTest_off();
                MPU6050_exist = false;
            }
            else
            {
                GPIO_SetBits(GPIOB, SCL);
                GPIO_SetBits(GPIOB, SDA);
                MPU6050_init(MPU6050_I2Cx, 90000, I2C_DutyCycle_2);
            }
            break;
        }
    }
}

void MPU6050_I2C_Configuration(I2C_TypeDef *I2Cx, uint32_t I2C_ClockSpeed, uint16_t I2C_DutyCycle)
{
    // 变量初始化
    I2C_InitTypeDef I2C_InitStruct;
    GPIO_InitTypeDef GPIO_InitStruct;
    MPU6050_I2Cx = I2Cx;
    MPU6050_exist = true;

    // 时钟配置
    // 配置 APB2EN 第 3 位为 IOPBEN 置1
    if (IS_BIT_0(RCC->APB2ENR, BIT(3)))
    {
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    }
    if (IS_BIT_0(RCC->APB2ENR, BIT(0)))
    {
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    }
    // 配置 APB1EN 第 21 位为 I2C1EN 置1
    if (I2Cx == I2C1)
    {
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
    }
    // 配置 APB1EN 第 22 位为 I2C2EN 置1
    if (I2Cx == I2C2)
    {
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
    }

    // 配置 GPIO 为开漏复用输出，速度为50MHz
    if (I2Cx == I2C1)
    {
        GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
    }
    if (I2Cx == I2C2)
    {
        GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
    }
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;
    GPIO_Init(GPIOB, &GPIO_InitStruct);
    GPIO_SetBits(GPIOB, GPIO_InitStruct.GPIO_Pin);

    // 根据初始化条件，配置 I2C
    I2C_InitStruct.I2C_ClockSpeed = I2C_ClockSpeed;
    I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;
    I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle;
    I2C_InitStruct.I2C_OwnAddress1 = 0x00;
    I2C_InitStruct.I2C_Ack = I2C_Ack_Enable;
    I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2C_Init(I2Cx, &I2C_InitStruct);

    I2C_Cmd(I2Cx, ENABLE);
}

void MPU6050_regInit()
{
    MPU6050_writeReg(PWR_MGMT_1, 0x80); // 复位
    Delay_ms(50);
    MPU6050_writeReg(PWR_MGMT_1, 0x00); // 唤醒
    MPU6050_writeReg(PWR_MGMT_2, 0x00);             // 关闭待机
    MPU6050_writeReg(INT_ENABLE, 0x00);             // 关闭中断
    MPU6050_setFilterBandwidth(MPU6050_BAND_94_HZ); // 设置低通滤波器
    MPU6050_writeReg(GYRO_CONFIG, 0x18);            // 陀螺仪满量程
    MPU6050_writeReg(ACCEL_CONFIG, 0x18);           // 加速度满量程
    MPU6050_writeReg(INT_PIN_CFG, 0x02);
    MPU6050_writeReg(USER_CTRL, 0x00);
}

/**
 * @brief
 *
 * @param I2Cx I2C口选择: I2C1 或 I2C2
 * @param I2C_ClockSpeed: 时钟频率: 低于 400000 (Hz)
 * @param I2C_DutyCycle 时钟占空比: I2C_DutyCycle_16_9(16:9) 或 I2C_DutyCycle_2(2:1)
 */
void MPU6050_init(I2C_TypeDef *I2Cx, uint32_t I2C_ClockSpeed, uint16_t I2C_DutyCycle)
{
    I2C_DeInit(I2Cx);
    MPU6050_I2C_Configuration(I2Cx, I2C_ClockSpeed, I2C_DutyCycle);
    MPU6050_regInit();
    MPU6050_initGyro();
}

/**
 * @brief 向寄存器中写入数据
 *
 * @param reg 寄存器地址
 * @param Data 写入的数据
 */
void MPU6050_writeReg(uint8_t reg, uint8_t Data)
{
    MPU6050_waitBusy();
    // 开始
    I2C_GenerateSTART(MPU6050_I2Cx, ENABLE);
    // 产生 EV5 事件，检测
    MPU6050_waitEvent(I2C_EVENT_MASTER_MODE_SELECT);
    // 地址 写模式
    I2C_Send7bitAddress(MPU6050_I2Cx, MPU6050_SLAVE_ADDRESS_0, I2C_Direction_Transmitter);
    // 自动 A 应答，下同
    // 产生 EV6 事件，检测
    MPU6050_waitEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
    // 产生 EV8_1 事件
    // 发送寄存器地址
    I2C_SendData(MPU6050_I2Cx, reg);
    // 等待 EV8 事件
    MPU6050_waitEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTING);
    // 发送数据
    I2C_SendData(MPU6050_I2Cx, Data);
    // 等待 EV8_2 事件
    MPU6050_waitEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED);
    // 结束
    I2C_GenerateSTOP(MPU6050_I2Cx, ENABLE);
}

/**
 * @brief 从寄存器中读出8位数据
 *
 * @param reg 寄存器地址
 * @return uint8_t 8位数据
 */
uint8_t MPU6050_readByte(uint8_t reg)
{
    uint8_t Data = 2;
    I2C_AcknowledgeConfig(MPU6050_I2Cx, ENABLE);
    MPU6050_waitBusy();
    // 开始
    I2C_GenerateSTART(MPU6050_I2Cx, ENABLE);
    // 产生 EV5 事件，检测
    MPU6050_waitEvent(I2C_EVENT_MASTER_MODE_SELECT);
    I2C_GenerateSTART(MPU6050_I2Cx, DISABLE);
    // 地址 写模式
    I2C_Send7bitAddress(MPU6050_I2Cx, MPU6050_SLAVE_ADDRESS_0, I2C_Direction_Transmitter);
    // 自动 A 应答，下同
    // 产生 EV6 事件，检测
    MPU6050_waitEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);

    // 产生 EV8_1 事件
    // 发送寄存器地址
    I2C_SendData(MPU6050_I2Cx, reg);
    // 等待 EV8_2 事件保证数据完全传输
    MPU6050_waitEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED);

    // 重复开始
    I2C_GenerateSTART(MPU6050_I2Cx, ENABLE);
    // 产生 EV5 事件，检测
    MPU6050_waitEvent(I2C_EVENT_MASTER_MODE_SELECT);

    // 地址 读模式
    I2C_Send7bitAddress(MPU6050_I2Cx, MPU6050_SLAVE_ADDRESS_0, I2C_Direction_Receiver);
    // 产生 EV6 事件，检测
    MPU6050_waitEvent(I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);

    // 提前设置 ACK 和 STOP
    I2C_AcknowledgeConfig(MPU6050_I2Cx, DISABLE);
    I2C_GenerateSTOP(MPU6050_I2Cx, ENABLE);

    // EV7 事件
    MPU6050_waitEvent(I2C_EVENT_MASTER_BYTE_RECEIVED);

    Data = I2C_ReceiveData(MPU6050_I2Cx);
    MPU6050_waitBusy();
    I2C_AcknowledgeConfig(MPU6050_I2Cx, ENABLE);

    return Data;
}

/**
 * @brief 从寄存器中读入16位数据
 *
 * @param reg 8位地址
 * @return uint16_t 16位数据
 */
uint16_t MPU6050_readWord(uint8_t reg)
{
    uint8_t Data_H = 2;
    uint8_t Data_L = 2;
    I2C_AcknowledgeConfig(MPU6050_I2Cx, ENABLE);
    MPU6050_waitBusy();

    // 开始
    I2C_GenerateSTART(MPU6050_I2Cx, ENABLE);
    // 产生 EV5 事件，检测
    MPU6050_waitEvent(I2C_EVENT_MASTER_MODE_SELECT);
    I2C_GenerateSTART(MPU6050_I2Cx, DISABLE);
    // 地址 写模式
    I2C_Send7bitAddress(MPU6050_I2Cx, MPU6050_SLAVE_ADDRESS_0, I2C_Direction_Transmitter);
    // 自动 A 应答，下同
    // 产生 EV6 事件，检测
    MPU6050_waitEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);

    // 产生 EV8_1 事件
    // 发送寄存器地址
    I2C_SendData(MPU6050_I2Cx, reg);
    // 等待 EV8_2 事件保证数据完全传输
    MPU6050_waitEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED);

    // 重复开始
    I2C_GenerateSTART(MPU6050_I2Cx, ENABLE);
    // 产生 EV5 事件，检测
    MPU6050_waitEvent(I2C_EVENT_MASTER_MODE_SELECT);

    // 地址 读模式
    I2C_Send7bitAddress(MPU6050_I2Cx, MPU6050_SLAVE_ADDRESS_0, I2C_Direction_Receiver);
    // 产生 EV6 事件，检测
    MPU6050_waitEvent(I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);

    // 等待 EV7 事件
    MPU6050_waitEvent(I2C_EVENT_MASTER_BYTE_RECEIVED);
    Data_H = I2C_ReceiveData(MPU6050_I2Cx);

    // 设置 ACK 和 STOP
    I2C_AcknowledgeConfig(MPU6050_I2Cx, DISABLE);
    I2C_GenerateSTOP(MPU6050_I2Cx, ENABLE);

    // EV7 事件
    MPU6050_waitEvent(I2C_EVENT_MASTER_BYTE_RECEIVED);

    Data_L = I2C_ReceiveData(MPU6050_I2Cx);
    MPU6050_waitBusy();
    I2C_AcknowledgeConfig(MPU6050_I2Cx, ENABLE);

    return (Data_H << 8) | Data_L;
}

void MPU6050_initGyro()
{
    uint16_t i;
    double temp;
    GYROZ_0 = 0;
    for (i = 0; i < 100; i++)
    {
        Delay_ms(1);
        GYROZ_0 += (double)(int16_t)(MPU6050_readWord(GYRO_ZOUT)) / 100;
    }
}

void MPU6050_setGyroRange(uint8_t MPU6050_RANGE)
{
    uint8_t temp = 0;
    temp = MPU6050_readByte(GYRO_CONFIG);
    temp |= (MPU6050_RANGE << 3);
    MPU6050_writeReg(GYRO_CONFIG, temp);
}

void MPU6050_setAccelRange(uint8_t MPU6050_RANGE)
{
    uint8_t temp = 0;
    temp = MPU6050_readByte(ACCEL_CONFIG);
    temp |= (MPU6050_RANGE << 3);
    MPU6050_writeReg(ACCEL_CONFIG, temp);
}

void MPU6050_setFilterBandwidth(uint8_t MPU6050_BAND)
{
    uint8_t temp = 0;
    temp = MPU6050_readByte(CONFIG);
    temp |= MPU6050_BAND;
    MPU6050_writeReg(CONFIG, temp);
}

double MPU6050_getGyro()
{
    double temp = (int16_t)(MPU6050_readWord(GYRO_ZOUT));
    return 2000 * (temp - GYROZ_0) / 32768;
}
